package com.ikas.ai.server.module.alarm.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.ikas.ai.consts.Consts;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.alarm.dao.UnitDeteriorationAlarmDAO;
import com.ikas.ai.server.module.alarm.enums.SolvedEnum;
import com.ikas.ai.server.module.alarm.model.UnitDeteriorationAlarm;
import com.ikas.ai.server.module.alarm.model.dto.UnitDeteriorationAlarmPageDTO;
import com.ikas.ai.server.module.alarm.model.enums.AlarmType;
import com.ikas.ai.server.module.assessment.dao.AssessWfResultMapper;
import com.ikas.ai.server.module.assessment.model.po.AssessWfResult;
import com.ikas.ai.server.module.condition.dao.WorkConditionFlowDao;
import com.ikas.ai.server.module.condition.model.WorkConditionFlow;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkFlowInstanceDao;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkInstanceStepDetailDao;
import com.ikas.ai.server.module.instance.enums.WorkInstanceStepDetailStateEnum;
import com.ikas.ai.server.module.instance.model.DorisWorkFlowInstance;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStepDetail;
import com.ikas.ai.server.module.risk.model.dto.RiskReportStatisticsDto;
import com.ikas.ai.server.module.steady.dao.SteadyAlarmDataMapper;
import com.ikas.ai.server.module.steady.model.po.SteadyAlarmData;
import com.ikas.ai.server.module.system.model.User;
import com.ikas.ai.utils.PageExUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 劣化预警
 *
 * @author tang.xuandong
 * @version 1.0.0
 * @date 2023/2/1 10:41
 */
@Service
@Slf4j
public class UnitDeteriorationAlarmService extends ServiceImpl<UnitDeteriorationAlarmDAO, UnitDeteriorationAlarm> {

    @Autowired
    private UnitDeteriorationAlarmDAO unitDeteriorationAlarmDAO;
    //    @Autowired
//    private WorkFlowInstanceDao workFlowInstanceDao;
    @Autowired
    private DorisWorkFlowInstanceDao dorisWorkFlowInstanceDao;
    @Autowired
    private DorisWorkInstanceStepDetailDao dorisWorkInstanceStepDetailDao;
    @Autowired
    private WorkConditionFlowDao workConditionFlowDao;
    @Autowired
    private AlarmCacheService alarmCacheService;
    @Autowired
    private AssessWfResultMapper assessWfResultMapper;
    @Autowired
    private SteadyAlarmDataMapper steadyAlarmDataMapper;

    public PageInfo<UnitDeteriorationAlarmPageDTO> queryAlarm(String machineNo, String wcDesc, String startWcBatch, String endWcBatch, Integer solved, String stepName, String meteCode) {
        List<UnitDeteriorationAlarm> unitDeteriorationAlarms = unitDeteriorationAlarmDAO.queryAlarm(machineNo, wcDesc, startWcBatch, endWcBatch, solved, stepName, meteCode);
        return PageExUtil.convert(new PageInfo<>(unitDeteriorationAlarms), this::coverToUaDTO);
    }

    private UnitDeteriorationAlarmPageDTO coverToUaDTO(UnitDeteriorationAlarm unitDeteriorationAlarm) {
        UnitDeteriorationAlarmPageDTO unitDeteriorationAlarmPageDTO = new UnitDeteriorationAlarmPageDTO();
        BeanUtils.copyProperties(unitDeteriorationAlarm, unitDeteriorationAlarmPageDTO);
        unitDeteriorationAlarmPageDTO.setExceptionResponseCost(new BigDecimal(unitDeteriorationAlarm.getExceptionResponseCost()).divide(new BigDecimal(1000), 3, RoundingMode.HALF_UP).doubleValue());
        String[] sub = unitDeteriorationAlarm.getWcDesc().split("\\(");
        unitDeteriorationAlarmPageDTO.setWfName(sub[0]);
        return unitDeteriorationAlarmPageDTO;
    }

    private List<UnitDeteriorationAlarmPageDTO> processData(List<UnitDeteriorationAlarm> unitDeteriorationAlarms) {
        List<UnitDeteriorationAlarmPageDTO> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(unitDeteriorationAlarms)) {
            list = unitDeteriorationAlarms.stream().map(u -> {
                UnitDeteriorationAlarmPageDTO unitDeteriorationAlarmPageDTO = new UnitDeteriorationAlarmPageDTO();
                BeanUtils.copyProperties(u, unitDeteriorationAlarmPageDTO);
                unitDeteriorationAlarmPageDTO.setExceptionResponseCost(new BigDecimal(u.getExceptionResponseCost()).divide(new BigDecimal(1000), 3, RoundingMode.HALF_UP).doubleValue());
                return unitDeteriorationAlarmPageDTO;
            }).collect(Collectors.toList());
            list.forEach(i -> {
                String[] sub = i.getWcDesc().split("\\(");
                i.setWfName(sub[0]);
            });
        }
        return list;
    }

    public void solved(Long id, User user) {
        UnitDeteriorationAlarm unitDeteriorationAlarm = unitDeteriorationAlarmDAO.selectById(id);
        if (Objects.isNull(unitDeteriorationAlarm)) {
            throw new BusinessException("不存在该记录！");
        }
        unitDeteriorationAlarm.setSolved(SolvedEnum.SOLVED.getSolved());
        unitDeteriorationAlarm.setUpdater(user.getId());
        unitDeteriorationAlarm.setUpdateTime(new Date());
        unitDeteriorationAlarm.setSolveUser(user.getUserName());
        unitDeteriorationAlarm.setSolveTime(new Date());
        updateById(unitDeteriorationAlarm);
        //更新redis
        int count = count(
                new LambdaQueryWrapper<UnitDeteriorationAlarm>()
                        .eq(UnitDeteriorationAlarm::getSolved, 0)
                        .eq(UnitDeteriorationAlarm::getMachineNo, unitDeteriorationAlarm.getMachineNo())
        );
        alarmCacheService.updateAlarm(AlarmType.UNIT_DETERIORATION, unitDeteriorationAlarm.getMachineNo(), count);
    }

    public List<UnitDeteriorationAlarmPageDTO> listByWc(String machineNo, String wcDesc, String wcBatch) {
        LambdaQueryChainWrapper<AssessWfResult> queryWrapper = new LambdaQueryChainWrapper<>(assessWfResultMapper);
        List<AssessWfResult> assessWfResultList = queryWrapper.eq(AssessWfResult::getMachineNo, machineNo)
                .eq(AssessWfResult::getBatch, wcBatch)
                .eq(AssessWfResult::getWfName, wcDesc)
                .eq(AssessWfResult::getTriggerFrom, 1)
                .gt(AssessWfResult::getStatus, 0)
                .list();
        //根据step_meteCode分组
        Map<String, AssessWfResult> wfResultMap = assessWfResultList.stream().collect(Collectors.toMap(k -> k.getStepName() + "_" + k.getMeteCode(), Function.identity(), (d1, d2) -> d1));
        LambdaQueryChainWrapper<UnitDeteriorationAlarm> wrapper = new LambdaQueryChainWrapper<>(unitDeteriorationAlarmDAO);
        List<UnitDeteriorationAlarm> deteriorationAlarmList = wrapper
                .eq(StringUtils.isNotEmpty(machineNo), UnitDeteriorationAlarm::getMachineNo, machineNo)
                .like(StringUtils.isNotEmpty(wcDesc), UnitDeteriorationAlarm::getWcDesc, wcDesc)
                .eq(StringUtils.isNotEmpty(wcBatch), UnitDeteriorationAlarm::getWcBatch, wcBatch)
                .list();
        deteriorationAlarmList.forEach(item -> {
            AssessWfResult assessWfResult = wfResultMap.get(item.getStepName() + "_" + item.getMeteCode());
            item.setModelExist(Objects.nonNull(assessWfResult));
        });
        return processData(deteriorationAlarmList);
    }

    @Transactional(rollbackFor = Exception.class)
    public void add(DorisWorkInstanceStepDetail workInstanceStepDetail) {
        log.info("start save unit-alarm:{}", JSON.toJSONString(workInstanceStepDetail));
        UnitDeteriorationAlarm unitDeteriorationAlarm = new UnitDeteriorationAlarm();
        DorisWorkFlowInstance workFlowInstance = dorisWorkFlowInstanceDao.selectById(workInstanceStepDetail.getWfInstanceId());
        if (Objects.nonNull(workFlowInstance)) {
            unitDeteriorationAlarm.setMachineNo(workFlowInstance.getMachineNo());
            unitDeteriorationAlarm.setWcBatch(workFlowInstance.getBatch());
        }
        Long wfId = workInstanceStepDetail.getWfId();
        WorkConditionFlow workConditionFlow = workConditionFlowDao.selectById(wfId);
        unitDeteriorationAlarm.setWcDesc(workConditionFlow.getWfDesc());
        unitDeteriorationAlarm.setStepName(workInstanceStepDetail.getStepName());
        unitDeteriorationAlarm.setMeteCodeDesc(workInstanceStepDetail.getMeteName());
        unitDeteriorationAlarm.setMeteCode(workInstanceStepDetail.getMeteCode());
        unitDeteriorationAlarm.setExceptionResponseCost((workInstanceStepDetail.getCostTime()));
        unitDeteriorationAlarm.setExceptionMsg(Consts.EXCEPTION_MSG);
        unitDeteriorationAlarm.setCreator(1L);
        unitDeteriorationAlarm.setCreateTime(new Date());
        unitDeteriorationAlarm.setUpdater(1L);
        unitDeteriorationAlarm.setUpdateTime(new Date());
        unitDeteriorationAlarm.setSolved(SolvedEnum.UN_SOLVED.getSolved());
        save(unitDeteriorationAlarm);
        //改变该实例步骤的状态state为3预警 t_work_instance_step_detail
        workInstanceStepDetail.setState(WorkInstanceStepDetailStateEnum.ALARM.getCode());
        workInstanceStepDetail.setUpdateTime(new Date());
        dorisWorkInstanceStepDetailDao.updateById(workInstanceStepDetail);
//        String wcBatch = unitDeteriorationAlarm.getWcBatch();
//        String wcDesc = unitDeteriorationAlarm.getWcDesc();
//        String machineNo = unitDeteriorationAlarm.getMachineNo();
//        LambdaQueryChainWrapper<WorkFlowInstance> wrapper = new LambdaQueryChainWrapper<>(workFlowInstanceDao);
//        List<WorkFlowInstance> list = wrapper.eq(StringUtils.isNotEmpty(machineNo), WorkFlowInstance::getMachineNo, machineNo)
//                .eq(StringUtils.isNotEmpty(wcDesc), WorkFlowInstance::getWfName, wcDesc)
//                .eq(StringUtils.isNotEmpty(wcBatch), WorkFlowInstance::getBatch, wcBatch)
//                .last("limit 1").list();
//        if (CollectionUtils.isEmpty(list)) {
//            log.info("该机组:{}在该工况:{}在该转换批次:{}没有流程实例", machineNo, wcDesc, wcBatch);
//        }
//        WorkFlowInstance workFlowInstance = list.get(0);
//        LambdaQueryChainWrapper<WorkInstanceStepDetail> detailLambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(workInstanceStepDetailDao);
//        List<WorkInstanceStepDetail> workInstanceStepDetails =
//                detailLambdaQueryChainWrapper
//                        .eq(WorkInstanceStepDetail::getWfInstanceId, workFlowInstance.getId())
//                        .eq(WorkInstanceStepDetail::getStepName, workInstanceStepDetail.getStepName())
//                        .eq(WorkInstanceStepDetail::getMeteCode, workInstanceStepDetail.getMeteCode())
//                        .list();
//        //只有一个更新
//        if (CollectionUtils.isNotEmpty(workInstanceStepDetails)) {
//            workInstanceStepDetails.forEach(i -> {
//                i.setState(WorkInstanceStepDetailStateEnum.ALARM.getCode());
//                i.setUpdateTime(new Date());
//                workInstanceStepDetailDao.updateById(i);
//            });
//        }
        //更新redis
        int count = count(
                new LambdaQueryWrapper<UnitDeteriorationAlarm>()
                        .eq(UnitDeteriorationAlarm::getSolved, 0)
                        .eq(UnitDeteriorationAlarm::getMachineNo, unitDeteriorationAlarm.getMachineNo())
        );
        alarmCacheService.updateAlarm(AlarmType.UNIT_DETERIORATION, unitDeteriorationAlarm.getMachineNo(), count);
    }

    public RiskReportStatisticsDto getUnitAlarmStatistics() {
        LambdaQueryChainWrapper<UnitDeteriorationAlarm> lambdaQueryWrapper = new LambdaQueryChainWrapper<>(unitDeteriorationAlarmDAO);
        List<UnitDeteriorationAlarm> unitDeteriorationAlarmList = lambdaQueryWrapper.in(UnitDeteriorationAlarm::getSolved, 1, 0).list();
        LambdaQueryChainWrapper<SteadyAlarmData> steadyAlarmDataLambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(steadyAlarmDataMapper);
        List<SteadyAlarmData> steadyAlarmDataList = steadyAlarmDataLambdaQueryChainWrapper.in(SteadyAlarmData::getSolved, 1, 0).list();
        long unitHandledCount = unitDeteriorationAlarmList.stream().filter(Objects::nonNull).filter(i -> 1 == i.getSolved()).count();
        long alarmHandledCount = steadyAlarmDataList.stream().filter(Objects::nonNull).filter(i -> 1 == i.getSolved()).count();
        long unitNotHandledCount = unitDeteriorationAlarmList.stream().filter(Objects::nonNull).filter(i -> 0 == i.getSolved()).count();
        long alarmNotHandledCount = steadyAlarmDataList.stream().filter(Objects::nonNull).filter(i -> 0 == i.getSolved()).count();
        Long handledCount = unitHandledCount + alarmHandledCount;
        Long notHandledCount = unitNotHandledCount + alarmNotHandledCount;
        return RiskReportStatisticsDto.builder().handledCount(handledCount).notHandledCount(notHandledCount).build();
    }

    @Transactional
    public void reOpenForTest(Long id) {
        UnitDeteriorationAlarm one = getById(id);
        one.setSolved(0);
        one.setSolveUser("");
        updateById(one);
        int count = count(
                new LambdaQueryWrapper<UnitDeteriorationAlarm>().eq(UnitDeteriorationAlarm::getSolved, 0).eq(UnitDeteriorationAlarm::getMachineNo, one.getMachineNo())
        );
        alarmCacheService.updateAlarm(AlarmType.UNIT_DETERIORATION, one.getMachineNo(), count);
    }
}
